package cn.com.yang.nio;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @Author 杨亿金
 * @Date 2021/12/21 20:52
 * @CopyRight
 * @Version
 */
public class NIOSelector {

    /**
     * 创建selector对象(NIO多路复用，server启动成功)
     * @param port
     * @return
     * @throws Exception
     */
    private Selector getSelector(int port) throws Exception{
        //创建selector对象
        Selector sel = Selector.open();

        //创建可选择通道，并配置为非阻塞模式
        ServerSocketChannel server = ServerSocketChannel.open();
        server.configureBlocking(false);
        //绑定通道指定端口
        ServerSocket socket = server.socket();
        InetSocketAddress address = new InetSocketAddress(port);
        socket.bind(address);

        //向selector注册感兴趣事件
        server.register(sel, SelectionKey.OP_ACCEPT);
        server.register(sel, SelectionKey.OP_READ);
        server.register(sel, SelectionKey.OP_WRITE);
        return sel;
    }

    /**
     * 开启监听
     * @param port
     * @param selector
     */
    public void listen(int port,Selector selector) throws Exception{
        System.out.println("listen on "+ port);
        //内部循环模式
        while (true){
            //该调用会阻塞，直到至少有一个事件发生
            selector.select();
            Set<SelectionKey> keys = selector.selectedKeys();
            Iterator<SelectionKey> iter = keys.iterator();
            while (iter.hasNext()){
                SelectionKey key = iter.next();
                iter.remove();
                process(selector,key);
            }
        }
    }

    /**
     * 根据不同的事件处理
     * @param key
     */
    private void process(Selector selector,SelectionKey key)throws Exception {
        //接受请求
        if (key.isAcceptable()){
            ServerSocketChannel server = (ServerSocketChannel) key.channel();
            SocketChannel channel = server.accept();
            channel.configureBlocking(false);
            //SelectionKey.OP_ACCEPT 这个值有点问题
            channel.register(selector,SelectionKey.OP_ACCEPT);
        //读取数据
        }else if(key.isReadable()){
            SocketChannel channel = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int len =channel.read(buffer);
            if (len>0){
                buffer.flip();
                String content = new String(buffer.array(),0,len);
                SelectionKey skey = channel.register(selector,SelectionKey.OP_READ);
                skey.attach(content);
            }else {
                channel.close();
            }
            buffer.clear();

            //写数据
        }else if(key.isWritable()){
            SocketChannel channel = (SocketChannel) key.channel();
            String content = (String) key.attachment();
            ByteBuffer block = ByteBuffer.wrap(("输出内容："+content).getBytes());
            if (block!=null){
                channel.write(block);
            }else {
                channel.close();
            }
        }
    }
}
